/*
 * Copyright © 2017 eqxiu.com 北京中网易企秀科技有限公司  All rights reserved.
 */

package cn.hermit.nio.http.server.builtin;

import cn.hermit.core.Disposable;
import cn.hermit.nio.http.Http;
import cn.hermit.nio.http.HttpException;
import cn.hermit.nio.http.server.HttpHandler;
import cn.hermit.nio.http.server.HttpRequest;
import cn.hermit.nio.http.server.HttpRouter;
import cn.hermit.nio.http.server.HttpServer;
import cn.hermit.nio.http.server.ResourceHttpHandler;
import cn.hermit.nio.http.server.ResourceSoftCache;
import com.sun.net.httpserver.HttpExchange;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author JackGao 高建国
 * @description //TODO 设计说明
 * @date 2/6/2017
 */
public class JavaHttpServer implements HttpServer, Disposable, Http {

    private static final Logger logger = Logger.getLogger(JavaHttpServer.class.getName());

    private com.sun.net.httpserver.HttpServer httpServer;

    private volatile boolean enableCors = false;

    private volatile HttpRouter router;

    private ResourceHttpHandler resourceHttpHandler = new ResourceHttpHandler();

    public JavaHttpServer(int port) throws IOException {
        httpServer = com.sun.net.httpserver.HttpServer.create();
        httpServer.bind(new InetSocketAddress(port), 0);
        httpServer.createContext("/", new com.sun.net.httpserver.HttpHandler() {
            @Override
            public void handle(HttpExchange httpExchange) throws IOException {
                long startTime = System.currentTimeMillis();
                logger.info("RequestURI : " + httpExchange.getRequestURI().toString());
                JavaHttpResponse response = new JavaHttpResponse(httpExchange);
                try {
                    HttpRequest request = new JavaHttpRequest(httpExchange);
                    HttpHandler handler = router.route(request);
                    if (handler == null) {
                        handler = resourceHttpHandler;
                    }
                    response.addHeader(CONNECTION, KEEP_ALIVE);
                    if (enableCors) {
                        response.addHeader("Access-Control-Allow-Origin", "*");
                        response.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, OPTIONS");
                        response.addHeader("Access-Control-Allow-Headers", "Content-Type, api_key, Authorization");
                    }
                    handler.handle(request, response);
                } catch (HttpException e) {
                    e.printStackTrace();
                    // any other, it's a 505 error
                    response.addHeader(CONTENT_LENGTH, 0);
                    response.setStatus(SERVER_ERROR_500);
                    logger.log(Level.SEVERE, "505 error", e);
                } finally {
                    response.flush();
                    logger.log(Level.INFO, "Total Time: " + (System.currentTimeMillis() - startTime) + "ms");
                }
            }
        });
        httpServer.start();
    }

    @Override
    public HttpServer router(HttpRouter router) {
        this.router = router;
        return this;
    }

    @Override
    public HttpServer staticRoot(String staticRoot) {
        resourceHttpHandler.setStaticRoot(staticRoot);
        return this;
    }

    @Override
    public HttpServer enableCors(boolean enableCors) {
        this.enableCors = enableCors;
        return this;
    }

    @Override
    public HttpServer refreshPageCache() {
        ResourceSoftCache.getInstance().clear();
        return this;
    }

    @Override
    public void destroy() {
        httpServer.stop(1000);
        ResourceSoftCache.getInstance().clear();
    }
}
